﻿using MCUPackage;
using MCUPackage.DesignEditor;
using MCUPackage.Utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace SxPackages.STC8.Models
{
	[Serializable]
	class SPIOptions : SPIOptionBase
	{
		private string mPins = "P5.4,P1.3,P1.4,P1.5";
		[DisplayName("使用引脚"),
		DefaultValue("P5.4,P1.3,P1.4,P1.5"),
		Description("本SPI口使用的引脚设置"),
		TypeConverter(typeof(StringCollectionConvertor)),
		MultiCollection(new string[] { "P5.4,P1.3,P1.4,P1.5", "P3.5,P3.4,P3.3,P3.2" })]
		public virtual string Pins
		{
			get => mPins;
			set
			{
				if (value != mPins)
				{
					if (SwitchPins(value, mPins))
					{
						mPins = value;
					}
				}
			}
		}

		[DisplayName("忽略SS引脚功能"),
		DefaultValue(true),
		Description("是否忽略SS引脚功能, 使用设置选项确定主从机模式")]
		public virtual bool SSIG { get; set; } = true;

		[DisplayName("大端模式"),
		DefaultValue(true),
		Description("是否使用大端模式收发数据, 大端模式先收发数据高位, 否则先收发数据低位")]
		public virtual bool MSB { get; set; } = true;

		private bool mMaster = true;
		[DisplayName("主从模式"),
		DefaultValue(true),
		Description("是否设置为主机模式, 否则为从机模式")]
		public virtual bool Master
		{
			get => mMaster;
			set
			{
				if (value != mMaster)
				{
					mMaster = value;
					if (Enable)
					{
						SetPins(mUsePins);
					}
				}
			}
		}

		[DisplayName("时钟极性"),
		DefaultValue(true),
		Description("时钟引脚空闲时是否为低电平, 否则为高电平")]
		public virtual bool CPOL { get; set; } = true;

		[DisplayName("时钟相位"),
		DefaultValue(true),
		Description("true为数据在时钟引脚的后时钟沿驱动, 前时钟沿采样, 否则为在前时钟沿驱动, 后时钟沿采样")]
		public virtual bool CPHA { get; set; } = true;

		[DisplayName("时钟频率"),
		DefaultValue(4),
		TypeConverter(typeof(IntCollectionConvertor)),
		IntCollection(new int[] { 2, 4, 8, 16 }),
		Description("时钟引脚的频率分频值, 主频除以本分频为SPI时钟频率")]
		public virtual int Speed { get; set; } = 4;

		[DisplayName("使能中断"),
		DefaultValue(false),
		Description("是否使能SPI中断")]
		public virtual bool EnableTI { get; set; } = false;

		[DisplayName("中断优先级"),
		Description("中断优先级等级设置"),
		DefaultValue(PriorityTypes.最低级)]
		public virtual PriorityTypes Priority { get; set; } = PriorityTypes.最低级;

		public SPIOptions(STC8HUSOP20 aParent) : base(aParent)
		{
			this.Type = SPITypes.SPI;
			mUsePins = TemplateHelper.GetPins(mPins);
		}

		protected override void SetPins(String[] aPins)
		{
			if (aPins == null || aPins.Length < 4)
			{
				return;
			}
			var opt = mParent.SetPinPurpose(aPins[0], PinPurpose.SPI_SS);
			if (opt != null)
			{
				if (this.Master)
				{
					opt.Mode = GPIOMode.Push;
				}
				else
				{
					opt.Mode = GPIOMode.Standard;
					opt.EnableUp = true;
				}
				opt.Level = GPIOLevel.High;
				opt.Speed = GPIOSpeed.Fast;
			}
			opt = mParent.SetPinPurpose(aPins[1], PinPurpose.SPI_MOSI);
			if (opt != null)
			{
				if (this.Master)
				{
					opt.Mode = GPIOMode.Push;
				}
				else
				{
					opt.Mode = GPIOMode.Standard;
					opt.EnableUp = true;
				}
				opt.Level = GPIOLevel.High;
				opt.Speed = GPIOSpeed.Fast;
			}
			opt = mParent.SetPinPurpose(aPins[2], PinPurpose.SPI_MISO);
			if (opt != null)
			{
				if (this.Master)
				{
					opt.Mode = GPIOMode.Standard;
					opt.EnableUp = true;
				}
				else
				{
					opt.Mode = GPIOMode.Push;
				}
				opt.Level = GPIOLevel.High;
				opt.Speed = GPIOSpeed.Fast;
			}
			opt = mParent.SetPinPurpose(aPins[3], PinPurpose.SPI_SCLK);
			if (opt != null)
			{
				if (this.Master)
				{
					opt.Mode = GPIOMode.Push;
					opt.Level = this.CPOL ? GPIOLevel.Low : GPIOLevel.High;
				}
				else
				{

					opt.Mode = GPIOMode.Standard;
					opt.EnableUp = true;
				}
				opt.Speed = GPIOSpeed.Fast;
			}
		}

		/// <summary>
		/// 初始化模板
		/// </summary>
		private const string TEMPLATE =
@"	attr.SPI_Enable    = ENABLE;				//SPI启动    ENABLE, DISABLE
	attr.SPI_SSIG      = {0};				//片选位     ENABLE, DISABLE
	attr.SPI_FirstBit  = {1};				//移位方向   SPI_MSB, SPI_LSB
	attr.SPI_Mode      = {2};		//主从选择   SPI_Mode_Master, SPI_Mode_Slave
	attr.SPI_CPOL      = {3};			//时钟相位   SPI_CPOL_High,   SPI_CPOL_Low
	attr.SPI_CPHA      = {4};		//数据边沿   SPI_CPHA_1Edge,  SPI_CPHA_2Edge
	attr.SPI_Speed     = SPI_Speed_{5};			//SPI速度    SPI_Speed_4, SPI_Speed_8, SPI_Speed_16, SPI_Speed_2
	SPI_Init(&attr);
	NVIC_SPI_Init({6}, {7});		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
	SPI_SW(SPI{8});	//SPI_P54_P13_P14_P15,SPI_P22_P23_P24_P25,SPI_P54_P40_P41_P43,SPI_P35_P34_P33_P32";

		public override Boolean AppendConfig(List<string[]> aLst)
		{
			if (!this.Enable)
			{
				return false;
			}

			string name = "SPI_Config";
			StringBuilder funcSb = new StringBuilder();
			funcSb.Append(TemplateHelper.GetFunctionCommit("SPI模块初始化"));
			funcSb.AppendLine($"PRIVATE void {name}(void)").AppendLine("{");
			funcSb.AppendLine("\tSPI_InitTypeDef attr;");

			Dictionary<string, List<string>> lst = new Dictionary<string, List<string>>();

			string pins = string.Empty;
			foreach (var pin in mUsePins)
			{
				var opt = mParent.GetPinOption(pin);
				if (opt != null)
				{
					opt.ToSTC8Dictionary(lst);
					pins += "_";
					pins += pin.Replace(".", "");
				}
			}
			if (lst.Count > 0)
			{
				funcSb.AppendLine();
				funcSb.Append(GPIOOptions.GetGPIOConfigs(lst));
			}

			funcSb.AppendLine();
			funcSb.AppendFormat(TEMPLATE, (!this.SSIG).ToEnable(), this.MSB ? "SPI_MSB" : "SPI_LSB",
								this.Master ? "SPI_Mode_Master" : "SPI_Mode_Slave",
								this.CPOL ? "SPI_CPOL_Low" : "SPI_CPOL_High",
								this.CPHA ? "SPI_CPHA_1Edge" : "SPI_CPHA_2Edge", this.Speed,
								this.EnableTI.ToEnable(), this.Priority.ToDescription(), pins);
			funcSb.AppendLine();

			funcSb.AppendLine("}");
			aLst.Add(new string[] { funcSb.ToString(), $"{name}();" });

			return true;
		}
	}
}
